home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
DCLAP 6d
/
dclap6d
/
network
/
ncsasock
/
sock_udp.c
< prev
next >
Wrap
Text File
|
1996-07-05
|
9KB
|
431 lines
/*
* BSD-style socket emulation library for the Mac
* Original author: Tom Milligan
* Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
*
* This source file is placed in the public domian.
* Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
*
* National Center for Supercomputing Applications
* 152 Computing Applications Building
* 605 E. Springfield Ave.
* Champaign, IL 61820
*/
#ifdef USEDUMP
# pragma load "Socket.dump"
#else
# include <Events.h>
# include <Memory.h>
# include <Errors.h>
# include <Types.h>
# include <OSUtils.h>
# include <Stdio.h>
# include <s_types.h>
# include <neti_in.h>
# include <neterrno.h>
# include <s_socket.h>
# include <s_time.h>
# include <s_uio.h>
# include "sock_str.h"
# include "sock_int.h"
#endif
extern SocketPtr sockets;
extern SpinFn spinroutine;
#if 0
/*
* asynchronous notification routine
*/
static int notified = 0;
static int lastNotifyCount = 0;
static StreamPtr notifyUdpStream;
static unsigned short notifyEventCode;
static Ptr notifyUserDataPtr;
static unsigned short notifyTerminReason;
static struct ICMPReport *notifyIcmpMsg;
pascal void sock_udp_notify(
StreamPtr udpStream,
unsigned short eventCode,
Ptr userDataPtr,
struct ICMPReport *icmpMsg)
{
notified++;
notifyUdpStream = udpStream;
notifyEventCode = eventCode;
notifyUserDataPtr = userDataPtr;
notifyIcmpMsg = icmpMsg;
}
static char *eventNames[] =
{
"event 0",
"data arrival",
"ICMP message"
};
static char *icmpMessages[] =
{
"net unreachable",
"host unreachable",
"protocol unreachable",
"port unreachable",
"fragmentation required",
"source route failed",
"time exceeded",
"parameter problem",
"missing required option"
};
int udpCheckNotify()
{
if (notified == lastNotifyCount)
return(0);
lastNotifyCount = notified;
dprintf("notify count is now %d\n",lastNotifyCount);
dprintf("stream %08x\n",notifyUdpStream);
dprintf("event %d '%s'\n",notifyEventCode,eventNames[notifyEventCode]);
if (notifyEventCode == UDPDataArrival)
dprintf("%d bytes\n",notifyTerminReason/*!?*/);
dprintf("icmp msg %08x\n",notifyIcmpMsg);
if (notifyEventCode == UDPICMPReceived)
{
dprintf("stream %08x\n",notifyIcmpMsg->streamPtr);
dprintf("local %08x/%d\n",notifyIcmpMsg->localHost,notifyIcmpMsg->localPort);
dprintf("remote %08x/%d\n",notifyIcmpMsg->remoteHost,notifyIcmpMsg->remotePort);
dprintf("%s\n",icmpMessages[notifyIcmpMsg->reportType]);
dprintf("optionalAddlInfo %04x\n",notifyIcmpMsg->optionalAddlInfo);
dprintf("optionalAddlInfoPtr %08x\n",notifyIcmpMsg->optionalAddlInfoPtr);
}
dprintf("userdata %s\n",notifyUserDataPtr);
return(1);
}
#endif
static int sock_udp_read_ahead(SocketPtr sp);
/*
* sock_udp_new_stream() - create the MacTCP stream for this socket. not
* called till the last minute while we wait for
* a bind to come in.
*
* called from whichever of connect, recv, send or
* select (can_recv or can_send) is called first.
*/
int sock_udp_new_stream(
SocketPtr sp)
{
OSErr io;
StreamHashEntPtr shep;
#if SOCK_UDP_DEBUG >= 2
dprintf("sock_udp_new_stream: sp %08x port %d\n", sp, sp->sa.sin_port);
#endif
if ( (io=xUDPCreate(sp, STREAM_BUFFER_SIZE, sp->sa.sin_port)) != noErr )
return(sock_err(io));
sp->sstate = SOCK_STATE_UNCONNECTED;
if ((shep = sock_new_shep(sp->stream)) != NULL)
{
shep -> stream = sp->stream;
shep -> socket = sp;
}
else
return -1;
sp-> recvd = 0;
sp-> recvBuf = 0;
sp-> asyncerr = inProgress;
/* start up the read ahead */
return(sock_udp_read_ahead(sp));
}
/*
* sock_udp_connect() - sets the peer process we will be talking to
*/
int sock_udp_connect(
SocketPtr sp,
struct sockaddr_in *addr)
{
int status;
/* make the stream if its not made already */
if (sp->sstate == SOCK_STATE_NO_STREAM)
{
status = sock_udp_new_stream(sp);
if (status != 0)
return(status);
}
/* record our peer */
sp->peer.sin_len = sizeof(struct sockaddr_in);
sp->peer.sin_addr.s_addr = addr->sin_addr.s_addr;
sp->peer.sin_port = addr->sin_port;
sp->peer.sin_family = AF_INET;
sp->sstate = SOCK_STATE_CONNECTED;
if (sp-> recvBuf) {
xUDPBfrReturn(sp);
}
/* flush the read-ahead buffer if its not from our new friend */
(void) sock_udp_can_recv(sp);
return(0);
}
static void sock_udp_read_ahead_done(UDPiopb *pb);
/*
* sock_udp_read_ahead() - start up the one packet read-ahead
*
* called from new_stream, recv and can_recv
*/
static int sock_udp_read_ahead(SocketPtr sp)
{
OSErr io;
io = xUDPRead(sp, (UDPIOCompletionProc)sock_udp_read_ahead_done);
if (io != noErr)
return(sock_err(io));
return(0);
}
/*
* sock_udp_return_buffer() - return the receive buffer to MacTCP
*/
static
int sock_udp_return_buffer(
SocketPtr sp)
{
OSErr io;
if (sp->recvBuf)
{
io = xUDPBfrReturn(sp);
if (io != noErr)
return(sock_err(io));
}
return(noErr);
}
/*
* sock_udp_recv()
*
* returns bytes received or -1 and errno
*/
int sock_udp_recv(
SocketPtr sp,
char *buffer,
int buflen,
int flags,
struct sockaddr_in *from,
int *fromlen)
{
#pragma unused(flags)
#if SOCK_UDP_DEBUG >= 2
dprintf("sock_udp_recv: sp %08x buflen %d state %04x\n", sp,buflen,sp->sstate);
#endif
/* make the stream if its not made already */
if (sp->sstate == SOCK_STATE_NO_STREAM)
{
int status = sock_udp_new_stream(sp);
if (status != 0)
return(status);
}
/* dont block a non-blocking socket */
if (sp->nonblocking && !sock_udp_can_recv(sp))
return(sock_err(EWOULDBLOCK));
SPIN(!sock_udp_can_recv(sp),SP_UDP_READ,0)
if (sp->asyncerr!=noErr)
return(sock_err(sp->asyncerr));
/* return the data to the user - truncate the packet if necessary */
buflen = min(buflen,sp->recvd);
BlockMove(sp->recvBuf,buffer,buflen);
#if (SOCK_UDP_DEBUG >= 7) || defined(UDP_PACKET_TRACE)
/*
hex_dump(buffer, buflen, "udp from %08x/%d\n",
sp->apb.pb.udp.csParam.receive.remoteHost,
sp->apb.pb.udp.csParam.receive.remotePort);
*/
#endif
if (from != NULL && *fromlen >= sizeof(struct sockaddr_in))
{
(*from) = sp->peer;
(*fromlen) = sizeof (struct sockaddr_in);
}
/* continue the read-ahead - errors which occur */
/* here will show up next time around */
(void) sock_udp_return_buffer(sp);
(void) sock_udp_read_ahead(sp);
return(buflen);
}
/*
* sock_udp_can_recv() - returns non-zero if a packet has arrived.
*
* Used by select, connect and recv.
*/
int sock_udp_can_recv(SocketPtr sp)
{
if (sp->sstate == SOCK_STATE_NO_STREAM)
{
int status = sock_udp_new_stream(sp);
if (status != 0)
return(-1);
}
if (sp->asyncerr == inProgress)
return(0);
return 1; // must recieve if not reading, even if an error occured - must handle error.
}
static void sock_udp_send_done(UDPiopb *pb);
/*
* sock_udp_send() - send the data in the (already prepared) wds
*
* returns bytes sent or -1 and errno
*/
int sock_udp_send(SocketPtr sp,struct sockaddr_in *to,char *buffer,int count,int flags)
{
#pragma unused(flags)
miniwds awds;
OSErr io;
#if SOCK_UDP_DEBUG >= 2
dprintf("sock_udp_send: %08x state %04x\n",sp,sp->sstate);
#endif
/* make the stream if its not made already */
if (sp->sstate == SOCK_STATE_NO_STREAM)
{
io = sock_udp_new_stream(sp);
if (io != 0)
return(io);
}
if ( count > UDP_MAX_MSG )
return sock_err(EMSGSIZE);
awds.terminus = 0;
awds.length = count;
awds.ptr = buffer;
// if no address passed, hope we have one already in peer field
if (to == NULL)
if (sp->peer.sin_len)
to = &sp->peer;
else
return (sock_err(EHOSTUNREACH));
io = xUDPWrite(sp, to->sin_addr.s_addr,to->sin_port, &awds,
(UDPIOCompletionProc)sock_udp_send_done);
if (io != noErr )
return(io);
// get sneaky. compl. proc sets ptr to nil on completion, and puts result code in
// terminus field.
SPIN(awds.ptr != NULL,SP_UDP_WRITE,count)
return (awds.terminus);
}
/*
* sock_udp_can_send() - returns non-zero if a write will not block
*/
int sock_udp_can_send(SocketPtr sp)
{
if (sp->sstate == SOCK_STATE_NO_STREAM)
{
if ( sock_udp_new_stream(sp) != 0 )
return(-1);
}
return (1);
}
/*
* sock_udp_close()
*/
int sock_udp_close(SocketPtr sp)
{
OSErr io;
if (sp->sstate == SOCK_STATE_NO_STREAM)
return(0);
io = xUDPRelease(sp);
if (io != noErr)
return(sock_err(io));
return(0);
}
#ifndef COMP_CODEWAR
#pragma segment SOCK_RESIDENT
#endif
/*
* Interrupt routines - MUST BE IN A RESIDENT SEGMENT! Most important to
* MacApp programmers
*/
/*
* sock_udp_send_done
*/
static void sock_udp_send_done(UDPiopb *pb)
{
((miniwds *)pb->csParam.send.wdsPtr)->terminus = pb->ioResult;
((miniwds *)pb->csParam.send.wdsPtr)->ptr = NULL;
}
/*
* sock_udp_read_ahead_done
*/
static void sock_udp_read_ahead_done(UDPiopb *pb)
{
register SocketPtr sp;
sp = sock_find_shep( pb->udpStream )->socket;
if (pb->ioResult == noErr) {
sp->recvBuf = pb->csParam.receive.rcvBuff;
sp->recvd = pb->csParam.receive.rcvBuffLen;
}
else {
sp-> recvd = 0;
sp-> recvBuf = 0;
}
sp->asyncerr = pb->ioResult;
}